#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/module.h>
//#include <linux/proc_fs.h>
//#include <linux/seq_file.h>
#include <asm/uaccess.h>  
#include <linux/kernel.h>
#include <linux/fs.h>
//#include<linux/sched.h>
#include <linux/slab.h>

//static char mybuf = 0;
struct list_head *myhead;
int myflag=0;
struct mystruct
{
	char data;
	struct list_head list;
};
struct list_head *mycurrent;
void mypush(char ch)
{
	
	struct mystruct	*tail;	
	tail=(struct mystruct*)kmalloc(sizeof(struct mystruct), GFP_KERNEL);
	//printk("push work ch %i\n", ch);
	tail->data = ch;
	list_add_tail(&(tail->list), myhead);
	mycurrent = &(tail->list);
	
}
char mypope(void)
{
	struct mystruct	*tmp;
	struct list_head *tmp2;
	char ch;
	//printk("pop work\n");
	if(mycurrent == myhead)
		return -1;
	tmp = list_entry (mycurrent, struct mystruct, list);
	ch = tmp->data;
	tmp2 = mycurrent;
	mycurrent = mycurrent->prev;
	list_del(tmp2);
	kfree(tmp);
	//printk("pop worked ch %i \n", ch);
	return ch;
}

static int myopen(struct inode *inode, struct  file *file)
{
	myflag=1;	
	return 0;
}

ssize_t stack_read(struct file *file, char *buffer, size_t count, loff_t *offset)
{
	char mybuf;
	if (myflag) 
	{
		mybuf=mypope();
		//printk("mybuf %c\n",mybuf);
		if(mybuf == -1)
		{
			printk("mybuf=-1\n");
			return 0;
		}
		put_user(mybuf, buffer);
		//printk("buffer %c\n",buffer[0]);
		//printk("flag not null\n");	
		myflag=0;
		return 1;
	}	
	else 
	{
		//printk("flag null\n");		
		return 0;
	}
	
}

ssize_t stack_write(struct file *file, const char *buffer, size_t count, loff_t *offset)
{
		
	char mybuf;
	int i=0;
	printk("count %i\n", count);
	for(i=0; i < count; i++)
	{
		get_user(mybuf, buffer+i);
		mypush(mybuf);
		//printk("write work mybuf %i\n", mybuf);
		
	}
	
			
	return i;
	
}

const struct file_operations stack_fops = {
	.read = stack_read,
	.write = stack_write,
	.owner = THIS_MODULE,
	.open = myopen,
};

static struct miscdevice stack_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "stack",
	.fops = &stack_fops,
};

int init_module(void)
{
	int ret;
	myhead=(struct list_head*)kmalloc(sizeof(struct list_head), GFP_KERNEL);	
	mycurrent=myhead;
	if(myhead==0)
	{
		printk("malloc returned 0 \n");
		return -1;
	}
	ret = misc_register(&stack_dev);
	if (ret < 0) {    
	printk("Registering  failed with %d\n", ret);
	return ret;
	}
	printk("<1>misk register passt %d\n", ret);
	INIT_LIST_HEAD(myhead);
	return 0;
}
void cleanup_module(void)
{
	misc_deregister(&stack_dev);
}
